<?php
// 应用公共文件
/**
 * @param  $url 获取内容的网页
 * @param  $ip 伪造的IP地址
 * @return 
 */
function curl_pull($url, $ip = '114.114.114.114',$cookie=false)
{
    $ch = curl_init();     // Curl 初始化   
    $timeout = 30;     // 超时时间：30s   
    $ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36';    // 伪造抓取 UA  
    curl_setopt($ch, CURLOPT_URL, $url);        // 设置 Curl 目标    
    curl_setopt($ch, CURLOPT_USERAGENT, $ua);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);          // Curl 请求有返回的值    
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);            // 设置抓取超时时间    
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);        // 跟踪重定向   
    curl_setopt($ch, CURLOPT_ENCODING, "");    // 设置编码   
    curl_setopt($ch, CURLOPT_REFERER, $url);   // 伪造来源网址    
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-FORWARDED-FOR:' . $ip, 'CLIENT-IP:' . $ip));  //伪造IP      curl_setopt($ch, CURLOPT_USERAGENT, $ua);   // 伪造ua     
    curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); // 取消gzip压缩    
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts   
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    $content = curl_exec($ch);
    curl_close($ch);    // 结束 Curl    
    return $content;    // 函数返回内容
}

/**
 * 使用ZipArchive压缩文件
 * @param $file  存放欲压缩的文件路径
 * @param $destination  生成zip文件的存放路径
 * @param $overwrite  是否覆盖 默认false
 * @return Bool
 */
function create_zip($files = array(), $destination = '', $overwrite = false): bool
{

    if (file_exists($destination) && !$overwrite) {
        return false;
    }

    $valid_files = array();
    if (is_array($files)) {
        foreach ($files as $file) {
            if (file_exists($file)) {
                $valid_files[] = $file;
            }
        }
    }

    if (count($valid_files)) {

        $zip = new ZipArchive();
        $b = $zip->open($destination, $overwrite ? ZipArchive::OVERWRITE : ZipArchive::CREATE);

        if ($b !== true) {
            return false;
        }

        foreach ($valid_files as $file) {
            $zip->addFile($file);
        }
        // echo 'The zip archive contains ', $zip->numFiles, ' files with a status of ', $zip->status;

        $zip->close();
        return file_exists($destination);
    } else {
        return false;
    }
}

/**
 * 使用ZipArchive解压缩文件
 * @param $zipFilePath   zip文件的路径
 * @param $destination   解压缩目标路径
 * @return bool
 */
function extract_zip($zip_file_path, $destination): bool
{
    if (!file_exists($zip_file_path)) {
        return false;
    }

    $zip = new ZipArchive();

    if ($zip->open($zip_file_path) === TRUE) {

        $zip->extractTo($destination);

        $zip->close();
        // echo "文件已成功解压缩到 $destination";
        return true;
    } else {
        // echo "无法打开 $zip_file_path";
        return false;
    }
}

/**
 * 移除emoji表情
 * @param string $str 含有emoji表情的字符串
 * @return string
 */
function remove_emoji_char($str)
{
    $mbLen = mb_strlen($str);
    $strArr = [];
    for ($i = 0; $i < $mbLen; $i++) {
        $mbSubstr = mb_substr($str, $i, 1, 'utf-8');
        if (strlen($mbSubstr) >= 4) {
            continue;
        }
        $strArr[] = $mbSubstr;
    }
    return implode('', $strArr);
}

/**
 * 查看字符串是否含有emoji表情
 * @param string $str 待检查的字符串
 * @return bool
 */
function have_emoji_char($str)
{
    $mbLen = mb_strlen($str);
    $strArr = [];
    for ($i = 0; $i < $mbLen; $i++) {
        $strArr[] = mb_substr($str, $i, 1, 'utf-8');
        if (strlen($strArr[$i]) >= 4) {
            return true;
        }
    }
    return false;
}

/**
 * 过滤掉emoji表情
 * @param string $str 含有特殊符号的字符串
 * @return string
 */
function filter_emoji($str)
{
    $str = preg_replace_callback('/./u', function (array $match) {
        return strlen($match[0]) >= 4 ? '' : $match[0];
    }, $str);
    return $str;
}


/**
 * 打印socketlog日志
 * @param mixed $log 调试输出内容
 * @param mixed $type 日志类型
 * @param string $css
 * @return string
 */
function slogi($log, $type = 'log', $css = '')
{
    if (is_string($type)) {
        $type = preg_replace_callback('/_([a-zA-Z])/', function ($matches) {
            return strtoupper($matches[1]);
        }, $type);

        if (method_exists('Slog', $type) || in_array($type, Slog::$log_types)) {
            return call_user_func(['\slog\Slog', $type], $log, $css);
        }
    }

    if (is_object($type) && 'mysqli' == get_class($type)) {
        return Slog::mysqliLog($log, $type);
    }

    if (is_resource($type) && ('mysql link' == get_resource_type($type) || 'mysql link persistent' == get_resource_type($type))) {
        return Slog::mysqlLog($log, $type);
    }

    if (is_object($type) && 'PDO' == get_class($type)) {
        return Slog::pdoLog($log, $type);
    }

    throw new \Exception($type . ' is not SocketLog method');
}

/**
 * 断点续传文件下载
 * @param string $file 文件绝对路径
 */
function download_with_break($file)
{
    str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $file);
    //检查文件是否存在
    if (empty($file) or !is_file($file)) {
        die('文件不存在');
    }
    $fileName = basename($file);
    //以只读和二进制模式打开文件
    $fp = @fopen($file, 'rb');
    if ($fp) {
        // 获取文件大小
        $file_size = filesize($file);
        //告诉浏览器这是一个文件流格式的文件
        header('content-type:application/octet-stream');
        header('Content-Disposition: attachment; filename=' . $fileName);
        // 断点续传
        $range = null;
        if (!empty($_SERVER['HTTP_RANGE'])) {
            $range = $_SERVER['HTTP_RANGE'];
            $range = preg_replace('/[\s|,].*/', '', $range);
            $range = explode('-', substr($range, 6));
            if (count($range) < 2) {
                $range[1] = $file_size;
            }
            $range = array_combine(array('start', 'end'), $range);
            if (empty($range['start'])) {
                $range['start'] = 0;
            }
            if (empty($range['end'])) {
                $range['end'] = $file_size;
            }
        }
        // 使用续传
        if ($range != null) {
            header('HTTP/1.1 206 Partial Content');
            header('Accept-Ranges:bytes');
            // 计算剩余长度
            header(sprintf('content-length:%u', $range['end'] - $range['start']));
            header(sprintf('content-range:bytes %s-%s/%s', $range['start'], $range['end'], $file_size));
            // fp指针跳到断点位置
            fseek($fp, sprintf('%u', $range['start']));
        } else {
            header('HTTP/1.1 200 OK');
            header('Accept-Ranges:bytes');
            header('content-length:' . $file_size);
        }
        while (!feof($fp)) {
            echo fread($fp, 4096);
            ob_flush();
        }
        fclose($fp);
    } else {
        die('File loading failed');
    }

    /**
     * 使用密钥生成HMAC-Sha1签名
     * @param array $params 请求参数
     * @param string $signKey 签名密钥
     * @return string
     */
    function hmac_sha1_sign($params, $signKey)
    {
        ksort($params);

        $paramString = '';
        foreach ($params as $key => $value) {
            if (is_null($value) || $value == '' || $key == 'sign') {
                continue;
            }
            $paramString .= $key . '=' . $value . '&';
        }
        $paramString = substr($paramString, 0, -1);
        $sign        = base64_encode(hash_hmac("sha1", $paramString, $signKey, $raw_output = true));
        return $sign;
    }
}


/**
 * 把数据加入层级
 * @param array $data 数据库取出的数据
 * @param int $pid    父id
 * @param int $level  层级
 * @param array 
 */
function r_sort($data, $pid = 0, $level = 0)
{
    // 静态变量
    static $r_arr = [];
    foreach ($data as $k => $v) {
        if ($v['pid'] == $pid) {
            $v['level'] = $level;
            $r_arr[] = $v;
            unset($data[$k]);
            r_sort($data, $v['id'], $level + 1);
        }
    }
    return $r_arr;
}
/**
 * 生成随机密码
 * @author  messha1r
 * @date    2025-09-08
 * @param   int $length    密码位数
 * @return  string     
 */
function generate_random_string($length = 10)
{
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+';
    $random_string = '';
    for ($i = 0; $i < $length; $i++) {
        $random_string .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $random_string;
}

/**
 * 计算文件大小
 * @author  messha1r
 * @date    2025-09-08
 * @param   string $file_path    文件路径
 * @return  string     
 */
function format_size($file_path)
{
    $size = filesize($file_path);
    $sizes = array(" Bytes", " KB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB");
    if ($size == 0) {
        return ('n/a');
    } else {
        return (round($size / pow(1024, ($i = floor(log($size, 1024)))), 2) . $sizes[$i]);
    }
}

/**
 * 获取当前请求页面url
 * @author  messha1r
 * @date    2025-09-08
 * @return  string     
 */
function current_page_url()
{
    $pageURL = 'http';
    if (!empty($_SERVER['HTTPS'])) {
        $pageURL .= "s";
    }
    $pageURL .= "://";
    if ($_SERVER["SERVER_PORT"] != "80") {
        $pageURL .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
    } else {
        $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
    }
    return $pageURL;
}

/**
 * Utf-8、gb2312都支持的汉字截取函数
 * @author  messha1r
 * @date    2025-09-08
 * @param string $string 原始字符串
 * @param int $sublen 字符串截取长度
 * @param int $start  开始截取的字符串索引
 * @param string $code 按照此编码格式截取
 * @return string
 */
function cut_str($string, $sublen, $start = 0, $code = 'UTF-8')
{
    if ($code == 'UTF-8') {
        $pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/";
        preg_match_all($pa, $string, $t_string);

        if (count($t_string[0]) - $start > $sublen)
            return join('', array_slice($t_string[0], $start, $sublen)) . "...";
        return join('', array_slice($t_string[0], $start, $sublen));
    } else {
        $start = $start * 2;
        $sublen = $sublen * 2;
        $strlen = strlen($string);
        $tmpstr = '';
        for ($i = 0; $i < $strlen; $i++) {
            if ($i >= $start && $i < ($start + $sublen)) {
                if (ord(substr($string, $i, 1)) > 129) {
                    $tmpstr .= substr($string, $i, 2);
                } else {
                    $tmpstr .= substr($string, $i, 1);
                }
            }
            if (ord(substr($string, $i, 1)) > 129) $i++;
        }
        if (strlen($tmpstr) < $strlen) $tmpstr .= "...";
        return $tmpstr;
    }
}